package com.tencent.trtcplugin;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;

import com.tencent.live.beauty.custom.ITXCustomBeautyProcesser;
import com.tencent.live.beauty.custom.ITXCustomBeautyProcesserFactory;
import com.tencent.live.beauty.custom.TXCustomBeautyDef;
import com.tencent.platformadapter.TencentRTCJni;
import com.tencent.trtc.TRTCCloud;
import com.tencent.trtc.TRTCCloudListener;
import com.tencent.trtcplugin.utils.ImageIO;
import com.tencent.trtcplugin.utils.CommonUtil;
import com.tencent.trtcplugin.utils.ObjectUtils;
import com.tencent.trtcplugin.utils.ProcessVideoFrame;
import com.tencent.trtcplugin.utils.TRTCLogger;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class TRTCCloudManager {
    private Context mContext;
    private MethodChannel mChannel;

    private ITXCustomBeautyProcesser mCustomBeautyProcesser;
    private ExecutorService mExecutor = Executors.newSingleThreadExecutor();
    private Handler mMainHandler = new Handler(Looper.getMainLooper());

    private Bitmap mMuteImage;

    TRTCCloudManager(Context context, MethodChannel channel) {
        mContext = context;
        mChannel = channel;
        channel.setMethodCallHandler(this::onMethodCall);
    }

    public void release() {
        mChannel.setMethodCallHandler(null);
        mMainHandler.removeCallbacksAndMessages(null);
        mExecutor.shutdown();
        if (mMuteImage != null) {
            mMuteImage.recycle();
        }
    }

    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        try {
            Method method = TRTCCloudManager.class.getDeclaredMethod(call.method, MethodCall.class, MethodChannel.Result.class);
            method.invoke(this, call, result);
        } catch (NoSuchMethodException e) {
            TRTCLogger.e("method=" + call.method + " | arguments=" + call.arguments + " | error=" + e);
        } catch (IllegalAccessException e) {
            TRTCLogger.e("method=" + call.method + " | arguments=" + call.arguments + " | error=" + e);
        } catch (Exception e) {
            TRTCLogger.e("method=" + call.method + " | arguments=" + call.arguments + " | error=" + e);
        }
    }

    private void initialize(MethodCall call, MethodChannel.Result result) {
        String s = TencentRTCJni.getStringToC();
        TRTCLogger.i("trtcFlutter initialize " + s);
        result.success(null);
    }

    private void snapshotVideo(MethodCall call, MethodChannel.Result result) {
        String userId = CommonUtil.getParam(call, result, "userId");
        int streamType = CommonUtil.getParam(call, result, "streamType");
        int sourceType = CommonUtil.getParam(call, result, "sourceType");
        String path = CommonUtil.getParam(call, result, "path");
        TRTCCloud.sharedInstance(mContext).snapshotVideo(userId, streamType, sourceType, new TRTCCloudListener.TRTCSnapshotListener() {
            @Override
            public void onSnapshotComplete(Bitmap bitmap) {
                mExecutor.execute(() -> {
                    ImageIO.SaveResult saveResult = ImageIO.save(mContext, bitmap, path);
                    mMainHandler.post(() -> notifySnapshotComplete(userId, saveResult));
                });
            }
        });
        result.success(null);
    }

    private void setVideoMuteImage(MethodCall call, MethodChannel.Result result) {
        String filePath = CommonUtil.getParam(call, result, "imagePath");
        int fps = CommonUtil.getParam(call, result, "fps");

        mExecutor.execute(() -> {
            if (mMuteImage != null) {
                mMuteImage.recycle();
            }
            mMuteImage = ImageIO.loadBitmapFromFile(mContext, filePath);
            mMainHandler.post(() -> {
                if (mMuteImage == null) {
                    TRTCLogger.e(" setVideoMuteImage | failed to load bitmap");
                } else {
                    TRTCCloud.sharedInstance(mContext).setVideoMuteImage(mMuteImage, fps);
                }
            });
        });

        result.success(null);
    }

    private void setWatermark(MethodCall call, MethodChannel.Result result) {
        String filePath = CommonUtil.getParam(call, result, "imagePath");
        int streamType = CommonUtil.getParam(call, result, "streamType");
        double x = CommonUtil.getParam(call, result, "x");
        double y = CommonUtil.getParam(call, result, "y");
        double width = CommonUtil.getParam(call, result, "width");

        mExecutor.execute(() -> {
            Bitmap watermark = ImageIO.loadBitmapFromFile(mContext, filePath);
            mMainHandler.post(() -> {
                if (watermark == null) {
                    TRTCLogger.e(" setWatermark | failed to load bitmap");
                } else {
                    TRTCCloud.sharedInstance(mContext).setWatermark(watermark, streamType, (float) x, (float) y, (float) width);
                }
            });
        });

        result.success(null);
    }

    private void enableVideoProcessByNative(MethodCall call, MethodChannel.Result result) {
        boolean enable = CommonUtil.getParam(call, result, "enable");
        ITXCustomBeautyProcesserFactory processFactory = TRTCPlugin.getBeautyProcesserFactory();
        if (mCustomBeautyProcesser == null) {
            mCustomBeautyProcesser = processFactory.createCustomBeautyProcesser();
        }
        TXCustomBeautyDef.TXCustomBeautyBufferType bufferType = mCustomBeautyProcesser.getSupportedBufferType();
        TXCustomBeautyDef.TXCustomBeautyPixelFormat pixelFormat = mCustomBeautyProcesser.getSupportedPixelFormat();
        if (enable) {
            ProcessVideoFrame processVideo = new ProcessVideoFrame(mCustomBeautyProcesser);
            int ret = TRTCCloud.sharedInstance(mContext).setLocalVideoProcessListener(ObjectUtils.convertTRTCPixelFormat(pixelFormat),
                    ObjectUtils.convertTRTCBufferType(bufferType), processVideo);
            result.success(ret);
        } else {
            int ret = TRTCCloud.sharedInstance(mContext).setLocalVideoProcessListener(ObjectUtils.convertTRTCPixelFormat(pixelFormat),
                    ObjectUtils.convertTRTCBufferType(bufferType), null);
            processFactory.destroyCustomBeautyProcesser();
            mCustomBeautyProcesser = null;
            result.success(ret);
        }
    }

    private void notifySnapshotComplete(String userId, ImageIO.SaveResult result) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        params.put("path", result.path);
        params.put("errCode", result.code);
        params.put("errMsg", result.message);

        mChannel.invokeMethod("onSnapshotComplete", params);
    }
}
